package com.qd.system.service.menu;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cdqidi.constant.ConstantDto;
import com.cdqidi.db.BaseService;
import com.cdqidi.dto.ApiResult;
import com.cdqidi.dto.ApiResultWrapper;
import com.cdqidi.dto.CacheKey;
import com.cdqidi.excel.ExcelExport;
import com.cdqidi.excel.util.ExportPage;
import com.cdqidi.exception.ApiException;
import com.cdqidi.util.RedisTemplateUtil;
import com.qd.common.sys.constant.Constants;
import com.qd.common.sys.constant.UserConstants;
import com.qd.common.sys.domain.entity.meun.MenuDTO;
import com.qd.common.sys.domain.tree.TreeSelect;
import com.qd.common.sys.enums.BaseTableEnum;
import com.qd.system.mapper.MenuMapper;
import com.qd.system.model.Menu;
import com.qd.system.service.dict.MbUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;

import static java.util.stream.Collectors.toList;

/**
 * @author sjk
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class MenuService extends BaseService<MenuMapper, Menu> {

    private static final String PREFIX_ID = "sys_menu_menuId_{0}";
    private static final String PREFIX_MENU_ALL = "sys_menu_all";
    private final RedisTemplateUtil<Menu> redisTemplateUtil;
    private final RedisTemplateUtil<MenuDTO> menuDtoRedisTemplateUtil;
    @Resource
    private HttpServletResponse response;

    /**
     * 删除，单个
     *
     * @param menuId 主键
     */
    @Transactional(rollbackFor = Exception.class)
    public void removeById(String menuId) {
        final Menu model = Optional.ofNullable(getById(menuId)).orElseThrow(() -> new ApiException("数据不存在,不能删除"));
        try {
            if (!super.removeById(menuId)) {
                throw new ApiException("删除失败");
            }
        } finally {
            clearCache(model);
            model.freeData();
        }
    }

    /**
     * 根据传入对象构建查询参数，判断是否存在
     *
     * @param dto 参数
     * @return 存在为true
     */
    @Transactional(readOnly = true)
    public Boolean isExists(MenuDTO dto) {
        final QueryWrapper<Menu> queryWrapper = createQueryWrapper(dto);
        final boolean exists = super.count(queryWrapper) > 0;
        queryWrapper.clear();
        return exists;
    }

    /**
     * 根据主键判断数据是否存在
     *
     * @param menuId 主键
     * @return 存在为true
     */
    @Transactional(readOnly = true)
    public Boolean isExistsById(String menuId) {
        boolean exists = false;
        if (StringUtils.hasLength(menuId)) {
            final Menu model = getById(menuId);
            exists = (null != model);
            if (exists) {
                model.freeData();
            }
        }
        return exists;
    }

    /**
     * 根据主键获取数据
     *
     * @param menuId 主键
     * @return 单条记录
     */
    @Transactional(readOnly = true)
    public Menu getById(String menuId) {
        final String key = RedisTemplateUtil.getRedisCacheKey(PREFIX_ID, menuId);
        return redisTemplateUtil.get(new CacheKey().setKey(key).setTimeout(ConstantDto.REDIS_TIME_OUT_DAY), () -> super.getById(menuId), Menu.class);
    }

    /**
     * 根据主键获取数据
     *
     * @param menuId 主键
     * @return 单条记录，转换成页面对象
     */
    @Transactional(readOnly = true)
    public MenuDTO getByIdDto(String menuId) {
        final Menu model = getById(menuId);
        if (null != model) {
            return modelToDto(model);
        }
        return null;
    }

    /**
     * 根据条件查询单条数据
     *
     * @param dto 查询参数
     * @return 单条记录
     */
    @Transactional(readOnly = true)
    public Menu getOne(MenuDTO dto) {
        final QueryWrapper<Menu> queryWrapper = createQueryWrapper(dto);
        final Menu model = super.getOne(queryWrapper);
        queryWrapper.clear();
        return model;
    }

    /**
     * 根据条件查询单条数据
     *
     * @param dto 查询参数
     * @return 单条记录，转换成页面对象
     */
    @Transactional(readOnly = true)
    public MenuDTO getOneDto(MenuDTO dto) {
        final Menu model = getOne(dto);
        if (null == model) {
            return null;
        }
        final MenuDTO newDto = modelToDto(model);
        model.freeData();
        return newDto;
    }

    /**
     * 根据条件查询列表数据
     *
     * @param dto 查询参数
     * @return 列表数据
     */
    @Transactional(readOnly = true)
    public List<Menu> getList(MenuDTO dto) {
        final QueryWrapper<Menu> queryWrapper = createQueryWrapper(dto);
        List<Menu> list = super.list(queryWrapper);
        queryWrapper.clear();
        return list;
    }

    /**
     * 根据条件查询列表数据
     *
     * @param dto 查询参数
     * @return 列表数据，转换成页面对象
     */
    @Transactional(readOnly = true)
    public List<MenuDTO> getListDto(MenuDTO dto) {
        return modelToDtoList(getList(dto));
    }

    /**
     * 分页数据
     *
     * @param page 分页对象
     * @param dto  查询参数
     * @return 分页信息
     */
    @Transactional(readOnly = true)
    public IPage<MenuDTO> page(Page<Menu> page, MenuDTO dto) {
        final QueryWrapper<Menu> queryWrapper = createQueryWrapper(dto, "men.");
        final IPage<MenuDTO> iPage = baseMapper.page(page, queryWrapper);
        queryWrapper.clear();
        return iPage;
    }

    /**
     * 导出Excel
     *
     * @param query 查询条件
     */
    @Transactional(readOnly = true)
    public void export(MenuDTO query){
        final ExportPage<Menu, MenuDTO> exportPage = new ExportPage<>();
        try{
            final List<MenuDTO> list = exportPage.getAllForPage(page -> page(page, query).getRecords());
            try {
                ExcelExport.downloadExcel(response, MenuDTO.class, () -> list);
            } catch (IOException e) {
                log.error("导出失败", e);
                throw new ApiException("导出失败");
            }
        }finally {
            exportPage.freeData();
        }
    }

    /**
     * 清空缓存
     *
     * @param model 数据库对象
     */
    public void clearCache(Menu model) {
        if (null == model) {
            return;
        }
        redisTemplateUtil.deleteByKey(RedisTemplateUtil.getRedisCacheKey(PREFIX_ID, model.getMenuId()));
        redisTemplateUtil.deleteByKey(RedisTemplateUtil.buildKey(PREFIX_MENU_ALL,true));
    }

    /**
     * 批量清空缓存
     *
     * @param list 数据库对象
     */
    public void clearCaches(List<Menu> list) {
        if (null == list || list.isEmpty()) {
            return;
        }
        redisTemplateUtil.deleteByKey(RedisTemplateUtil.buildKey(PREFIX_MENU_ALL,true));
        List<String> ids = list.stream().map(model -> RedisTemplateUtil.getRedisCacheKey(PREFIX_ID, model.getMenuId())).collect(toList());
        if (!ids.isEmpty()) {
            redisTemplateUtil.deleteByKey(ids);
            ids.clear();
        }
    }

    /**
     * 数据库对象转页面对象
     *
     * @param model 数据库对象
     * @return 页面对象
     */
    @Transactional(readOnly = true)
    public MenuDTO modelToDto(Menu model) {
        if (null == model) {
            return null;
        }
        final MenuDTO dto = new MenuDTO();
        dto.setMenuId(model.getMenuId());
        dto.setParentId(model.getParentId());
        dto.setMenuCode(model.getMenuCode());
        dto.setMenuName(model.getMenuName());
        dto.setOrderNum(model.getOrderNum());
        dto.setMenuUrl(model.getMenuUrl());
        dto.setMenuIcon(model.getMenuIcon());
        dto.setMenuStatus(model.getMenuStatus());
        dto.setPerms(model.getPerms());
        dto.setComponent(model.getComponent());
        dto.setAddTime(model.getAddTime());
        dto.setUpdateTime(model.getUpdateTime());
        dto.setMenuType(model.getMenuType());
        dto.setVisible(model.getVisible());
        dto.setIsFrame(model.getIsFrame());
        dto.setButtonType(model.getButtonType());
        buildDisplay(dto);
        return dto;
    }

    /**
     * 页面对象转数据库对象
     *
     * @param dto 页面对象
     * @return 数据库对象
     */
    public Menu dtoToModel(MenuDTO dto) {
        if (null == dto) {
            return null;
        }
        final Menu model = new Menu();
        model.setMenuId(dto.getMenuId());
        model.setParentId(dto.getParentId());
        model.setMenuCode(dto.getMenuCode());
        model.setMenuName(dto.getMenuName());
        model.setOrderNum(dto.getOrderNum());
        model.setMenuUrl(dto.getMenuUrl());
        model.setMenuIcon(dto.getMenuIcon());
        model.setMenuStatus(dto.getMenuStatus());
        model.setPerms(dto.getPerms());
        model.setComponent(dto.getComponent());
        model.setAddTime(dto.getAddTime());
        model.setUpdateTime(dto.getUpdateTime());
        model.setMenuType(dto.getMenuType());
        model.setVisible(dto.getVisible());
        model.setIsFrame(dto.getIsFrame());
        model.setButtonType(dto.getButtonType());
        return model;
    }

    /**
     * 码表转换
     *
     * @param dto 页面对象
     */
    @Transactional(readOnly = true)
    public void buildDisplay(MenuDTO dto) {
        if (StringUtils.hasLength(dto.getParentId()) && dto.getParentId().equals(Constants.DEFAULT_TREE_PARENT_ID)) {
            dto.setParentIdDisplay(idToDisplay(dto.getParentId()));
        }
        if (StringUtils.hasLength(dto.getMenuType())) {
            dto.setMenuTypeDisplay(MbUtil.idToDisplay(dto.getMenuType()));
        }
        if (null != dto.getMenuStatus()) {
            dto.setMenuStatusDisplay(MbUtil.idToDisplay(dto.getMenuStatus()));
        }
        if (StringUtils.hasLength(dto.getVisible())) {
            dto.setVisibleDisplay(MbUtil.idToDisplay(dto.getVisible()));
        }
        if (StringUtils.hasLength(dto.getIsFrame())) {
            dto.setIsFrameDisplay(MbUtil.idToDisplay(dto.getIsFrame()));
        }
        if (StringUtils.hasLength(dto.getButtonType())) {
            dto.setButtonTypeDisplay(MbUtil.idToDisplay(dto.getButtonType()));
        }
    }

    /**
     * 数据库对象转页面对象
     *
     * @param list 数据库对象
     * @return 页面对象
     */
    public List<MenuDTO> modelToDtoList(List<Menu> list) {
        if (null == list) {
            return Collections.emptyList();
        }
        return list.stream().map(this::modelToDto).collect(toList());
    }

    /**
     * 页面对象转数据库对象
     *
     * @param list 页面对象
     * @return 数据库对象
     */
    public List<Menu> dtoToModelList(List<MenuDTO> list) {
        if (null == list) {
            return Collections.emptyList();
        }
        return list.stream().map(this::dtoToModel).collect(toList());
    }

    /**
     * 拼装查询参数，除了主键的其他字段会自动加入进来
     *
     * @param dto 查询参数，不为空的属性会被自动加入
     */
    public QueryWrapper<Menu> createQueryWrapper(MenuDTO dto) {
        return createQueryWrapper(dto, "");
    }

    /**
     * 拼装查询参数，除了主键的其他字段会自动加入进来
     *
     * @param dto        查询参数，不为空的属性会被自动加入
     * @param tableAlias 表别名
     */
    public QueryWrapper<Menu> createQueryWrapper(MenuDTO dto, String tableAlias) {
        final QueryWrapper<Menu> queryWrapper = new QueryWrapper<>();
        if (null != dto) {
            if (StringUtils.hasLength(tableAlias) && tableAlias.charAt(tableAlias.length() - 1) != '.') {
                tableAlias += ".";
            }
            if (StringUtils.hasLength(dto.getParentId())) {
                queryWrapper.eq(tableAlias + Constants.PARENT_ID, dto.getParentId());
            }
            if (StringUtils.hasLength(dto.getMenuCode())) {
                queryWrapper.like(tableAlias + "menu_code", dto.getMenuCode());
            }
            if (StringUtils.hasLength(dto.getMenuName())) {
                queryWrapper.like(tableAlias + "menu_name", dto.getMenuName());
            }
            if (null != dto.getMenuStatus()) {
                queryWrapper.eq(tableAlias + "menu_status", dto.getMenuStatus());
            }
            if (StringUtils.hasLength(dto.getPerms())) {
                queryWrapper.eq(tableAlias + "perms", dto.getPerms());
            }
            if (StringUtils.hasLength(dto.getComponent())) {
                queryWrapper.eq(tableAlias + "component", dto.getComponent());
            }
            final String menuType = dto.getMenuType();
            if (StringUtils.hasLength(menuType)) {
                final Object[] menuTypes = menuType.split(",");
                if (menuTypes.length == 1) {
                    queryWrapper.eq(tableAlias + "menu_type", dto.getMenuType());
                } else {
                    queryWrapper.in(tableAlias + "menu_type", menuTypes);
                }
            }
            if (StringUtils.hasLength(dto.getButtonType())) {
                queryWrapper.eq(tableAlias + "button_type", dto.getButtonType());
            }
            if (StringUtils.hasLength(dto.getVisible())) {
                queryWrapper.eq(tableAlias + "visible", dto.getVisible());
            }
            if (StringUtils.hasLength(dto.getIsFrame())) {
                queryWrapper.eq(tableAlias + "is_frame", dto.getIsFrame());
            }
            if (StringUtils.hasLength(dto.getBeginTime())) {
                queryWrapper.apply("date_format(" + tableAlias + "add_time,'%Y-%m-%d') >= {0}", dto.getBeginTime());
            }
            if (StringUtils.hasLength(dto.getEndTime())) {
                queryWrapper.apply("date_format(" + tableAlias + "add_time,'%Y-%m-%d') <= {0}", dto.getEndTime());
            }
        }
        queryWrapper.orderByAsc(tableAlias + "parent_id");
        queryWrapper.orderByAsc(tableAlias + "order_num");
        return queryWrapper;
    }

//    /**
//     * 获得人员对应的菜单信息
//     *
//     * @param personId 人员ID
//     * @param menuDto  查询条件
//     * @return 菜单列表
//     */
//    @Transactional(readOnly = true)
//    public List<MenuDto> getMenuDto(String personId, MenuDto menuDto) {
//        menuDto.setMenuStatus(Constants.STATUS_ENABLE);
//        List<MenuDto>  menuList = super.getBaseMapper().getMenuTreeAll(createQueryWrapper(menuDto));
//        if (SecurityUtils.isAdmin(personId)) {
//           return menuList;
//        } else {
//            final QueryWrapper<Menu> queryWrapper = createQueryWrapper(menuDto);
//            queryWrapper.eq("pr.person_id", personId);
//            menuList = super.getBaseMapper().getMenuListByUserId(personId, queryWrapper);
//            queryWrapper.clear();
//        }
//        if (menuList.isEmpty()) {
//            return Collections.emptyList();
//        }
//        return menuList;
//    }

    /**
     * 处理菜单
     *
     * @param list 菜单列表
     * @return 菜单列表
     */
    public List<MenuDTO> buildMenu(List<MenuDTO> list) {
        final List<MenuDTO> returnList = new ArrayList<>(list.size());
        for (MenuDTO menu : list) {
            // 一、根据传入的某个父节点ID,遍历该父节点的所有子节点
            if (menu.getParentId().equals(Constants.DEFAULT_TREE_PARENT_ID)) {
                recursionFn(list, menu);
                returnList.add(menu);
            }
        }
        return returnList;
    }

    /**
     * 递归处理菜单子节点信息
     *
     * @param menus 菜单列表信息
     * @param menu  单个信息
     */
    private void recursionFn(List<MenuDTO> menus, MenuDTO menu) {
        // 得到子节点列表
        final List<MenuDTO> childList = getChildList(menus, menu);
        menu.setChildren(childList);
        for (MenuDTO tChild : childList) {
            if (hasChild(menus, tChild)) {
                recursionFn(menus, tChild);
            }
        }
    }

    /**
     * 构建前端所需要下拉树结构
     *
     * @param menus 菜单列表
     * @return 下拉树结构列表
     */
    public List<TreeSelect> buildMenuTreeSelect(List<MenuDTO> menus) {
        if (menus.isEmpty()) {
            return Collections.emptyList();
        }
        final List<MenuDTO> menuTrees = buildMenu(menus);
        return menuTrees.stream().map(TreeSelect::new).collect(toList());
    }

    /**
     * 是否还有子节点
     *
     * @param menus 菜单集合
     * @param menu  单个菜单
     * @return true or false
     */
    private boolean hasChild(List<MenuDTO> menus, MenuDTO menu) {
        return !getChildList(menus, menu).isEmpty();
    }

    /**
     * 得到子节点列表
     */
    private List<MenuDTO> getChildList(List<MenuDTO> list, MenuDTO menu) {
        final List<MenuDTO> childList = new ArrayList<>();
        for (MenuDTO menuDto : list) {
            if (menuDto.getParentId().equals(menu.getMenuId())) {
                childList.add(menuDto);
            }
        }
        return childList;
    }

    /**
     * 是否存在菜单子节点
     *
     * @param menuId 菜单ID
     * @return 结果
     */
    public boolean hasChildByMenuId(String menuId) {
        final QueryWrapper<Menu> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("parent_id", menuId);
        final Long result = super.getBaseMapper().selectCount(queryWrapper);
        queryWrapper.clear();
        return null != result && result > 0;
    }

    /**
     * 唯一性约束验证(不用验证名字是否重复)
     *
     * @param menu 菜单信息
     * @return true or false
     */
    public boolean checkMenuNameUnique(MenuDTO menu) {
//        boolean isExists;
//        final QueryWrapper<Menu> queryWrapper = new QueryWrapper<>();
//        if (StringUtils.hasLength(menu.getParentId())) {
//            queryWrapper.eq("parent_id", menu.getParentId());
//        }
//        queryWrapper.eq("menu_name", menu.getMenuName());
//        final Menu menuModel = getOne(queryWrapper);
//        if (null == menuModel) {
//            isExists = false;
//        } else {
//            if (StringUtils.hasLength(menu.getMenuId())) {
//                isExists = !menuModel.getMenuId().equals(menu.getMenuId());
//            } else {
//                isExists = true;
//            }
//            menuModel.freeData();
//        }
//        return isExists;
        return false;
    }

    /**
     * 保存菜单
     *
     * @param menu 菜单信息
     * @return 菜单对象
     */
    @Transactional(rollbackFor = Exception.class)
    public MenuDTO saveMenu(MenuDTO menu) {
        if (checkMenuNameUnique(menu)) {
            throw new ApiException("菜单名称已经存在");
        }
        menu.setAddTime(LocalDateTime.now());
        checkParam(menu);
        final Menu model = dtoToModel(menu);
        try{
            save(model);
            clearAllMenu();
        }finally {
            clearCache(model);
        }
        return modelToDto(model);
    }

    /**
     * 更新菜单
     *
     * @param menu 菜单信息
     * @return true or false
     */
    @Transactional(rollbackFor = Exception.class)
    public ApiResultWrapper<Object> updateMenu(MenuDTO menu) {
        if (checkMenuNameUnique(menu)) {
            throw new ApiException("菜单名称已经存在");
        }
        checkParam(menu);
        final Menu oldModel = Optional.ofNullable(getById(menu.getMenuId())).orElseThrow(() -> new ApiException("ID不存在,不能更新"));
        final Menu model = dtoToModel(menu);
        try{
            updateById(model);
            clearAllMenu();
        }finally {
            clearCache(oldModel);
            oldModel.freeData();
            model.freeData();
        }
        return ApiResult.success();
    }

    /**
     * 批量添加
     *
     * @param mList 数据库对象
     */
    @Transactional(rollbackFor = Exception.class)
    public void saveBatch(List<Menu> mList) {
        try {
            if (!super.saveBatch(mList)) {
                throw new ApiException("批量添加失败");
            }
        } finally {
            clearCaches(mList);
        }
    }

    /**
     * 批量更新
     *
     * @param mList 数据库对象
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateBatchIds(List<Menu> mList) {
        final List<String> ids = mList.stream().map(Menu::getMenuId).collect(toList());
        final List<Menu> historyModelList = checkIds(ids);
        try {
            if (!super.updateBatchById(mList)) {
                throw new ApiException("批量更新失败");
            }
        } finally {
            clearCaches(historyModelList);
            historyModelList.clear();
            ids.clear();
        }
    }

    private void clearAllMenu() {
        redisTemplateUtil.deleteByKey(RedisTemplateUtil.buildKey(PREFIX_MENU_ALL,true));
    }

    /**
     * 检查参数
     *
     * @param menu 菜单数据
     */
    private void checkParam(MenuDTO menu) {
        final String parentId = menu.getParentId();
        if (!StringUtils.hasLength(parentId)) {
            menu.setParentId("0");
        }
        final String menuType = menu.getMenuType();
        if (StringUtils.hasLength(menuType)) {
            if (MbUtil.isNotExists(menuType, BaseTableEnum.MENU_TYPE)) {
                throw new ApiException("菜单类型值不存在");
            }
        }
        if (UserConstants.TYPE_BUTTON.equals(menuType)) {
            final String buttonType = menu.getButtonType();
            if (StringUtils.hasLength(buttonType)) {
                if (MbUtil.isNotExists(buttonType, BaseTableEnum.BUTTON_TYPE)) {
                    throw new ApiException("按钮类型值不存在");
                }
            }
        }
        final String isFrame = menu.getIsFrame();
        if (StringUtils.hasLength(isFrame)) {
            if (MbUtil.isNotExists(isFrame, BaseTableEnum.SF)) {
                throw new ApiException("是否外链值不存在");
            }
        }
        final Integer menuStatus = menu.getMenuStatus();
        if (null != menuStatus) {
            if (!MbUtil.isExists(menuStatus)) {
                throw new ApiException("菜单状态值不存在");
            }
        }
        final String visible = menu.getVisible();
        if (StringUtils.hasLength(visible)) {
            if (MbUtil.isNotExists(visible, BaseTableEnum.VISIBLE)) {
                throw new ApiException("显示状态值不存在");
            }
        }
    }

    /**
     * 根据菜单ID返回菜单名字
     *
     * @param menuId 菜单ID
     * @return 菜单名字
     */
    @Transactional(readOnly = true)
    public String idToDisplay(String menuId) {
        String display = "";
        if (StringUtils.hasLength(menuId)) {
            final Menu menu = getById(menuId);
            display = (null == menu ? "" : menu.getMenuName());
        }
        return display;
    }

    /**
     * 获得所有菜单
     *
     * @param menu 查询条件
     * @return 菜单信息
     */
    @Transactional(readOnly = true)
    public List<MenuDTO> getAll(MenuDTO menu) {
        final QueryWrapper<Menu> queryWrapper = createQueryWrapper(menu, "men.");
        final List<MenuDTO> list = baseMapper.getMenuTreeAll(queryWrapper);
        if (list.isEmpty()) {
            return Collections.emptyList();
        }
        menu.freeData();
        queryWrapper.clear();
        return buildMenu(list);
    }

    /**
     * 获得全部列表数据
     *
     * @return 列表
     */
    @Transactional(readOnly = true)
    public List<MenuDTO> getMenuTreeAll() {
        return menuDtoRedisTemplateUtil.getList(new CacheKey().setKey(RedisTemplateUtil.buildKey(PREFIX_MENU_ALL,true)), () -> {
            final QueryWrapper<Menu> queryWrapper = new QueryWrapper<>();
            queryWrapper.orderByAsc("parent_id","order_num");
            return baseMapper.getMenuTreeAll(queryWrapper);
        }, MenuDTO.class);
    }

    /**
     * 批量检查主键在数据库中是否存在
     *
     * @param ids 主键集合
     * @return 主键查询出来的集合
     */
    public List<Menu> checkIds(List<String> ids) {
        if (null == ids || ids.isEmpty()) {
            throw new ApiException("ids不能为空");
        }
        final List<Menu> list = super.listByIds(ids);
        if (list.isEmpty()) {
            throw new ApiException("ids不存在" + Arrays.toString(ids.toArray()));
        }
        if (ids.size() == list.size()) {
            return list;
        }
        List<String> dbIds = list.stream().map(Menu::getMenuId).collect(toList());
        final List<String> notExistsList = ids.stream().filter(id -> !dbIds.contains(id)).collect(toList());
        dbIds.clear();
        if (!notExistsList.isEmpty()) {
            throw new ApiException("ids不存在" + Arrays.toString(notExistsList.toArray()));
        }
        return list;
    }
}